/***************************************************************************
*   Copyright (C) 2005 by Alexander Nemish                              *
*   atlanter@gmail.com                                                  *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU General Public License     *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/
#include <kdebug.h>
#include <qfontmetrics.h>
#include <qregexp.h>
#include <qpainter.h>
#include <vector>

#include "renderer.h"

#define START_PARAGRAPH '\v'
#define END_PARAGRAPH '\a'

Renderer::Renderer():
		m_pageCount( 0 ),
		m_linesPerPage( 0 ),
		m_empty(true)
{}


Renderer::~Renderer()
{
	TParagsIter end = m_parags.end();
	for (TParagsIter it = m_parags.begin(); it != end; ++it)
		delete (*it);
}

void Renderer::load( const QStringList & list )
{
	m_empty = true;
	
	if (list.isEmpty())
		return;
	
	m_text = list;
	m_empty = false;
	
	typedef QStringList::iterator TStringIter;
	TStringIter end = m_text.end();
	for (TStringIter it = m_text.begin(); it != end; ++it)
		(*it).replace(QChar( '\t' ), "        ");
	
	render();	
}

void Renderer::render()
{
	if (m_empty) return;
	m_lines.clear();
    kdDebug() << "setuping text... count = " << m_text.count() << endl;
	//size_t lineCount = m_text.count();
	int curLine = 0;
	//double percent = 0.0;
	QString string;
	TStringIter it(m_text.constBegin());

	while (it != m_text.constEnd())
	{
		//get string
		string = *it;
		//process string until paragraph ends
		while (++it != m_text.constEnd())
		{
			QChar const ch((*it)[0]);
			++curLine;
			//insert empty lines
			if ((*it).isEmpty())
				break;
			//check whether paragraph not ends
			if (ch != ' ' && ch != '-')
			{
				string += " " + *it;
			}
			else break;
		}
		//kdDebug() << str << endl;
		m_parags.push_back(new Paragraph(string));
		parseString(string);
		//emit loaded((int) curLine/lineCount );
	}

	m_linesPerPage = m_pageSize.height() / ( QFontMetrics( font() ).height() );
	m_pageCount = m_lines.count() / m_linesPerPage;
	kdDebug() << "done" << endl;
}

void Renderer::parseString(const QString & string1)
{
	//TODO: rewrite this ugly stuff
	QString string(string1);
	QFontMetrics fm(font());
	const int min_len = fm.width( "." );
	//calc approx string width
	const unsigned int avg_len = m_pageSize.width() / min_len;
	unsigned int len;
	while (fm.width(string) > m_pageSize.width())
	{
		len = avg_len;
		//turn left if missed
		while ( ( fm.width( string.left( len ) ) > m_pageSize.width() ) && ( len > 0 ) )
			--len;
		//turn right if missed
		while ( ( fm.width( string.left( len ) ) <= m_pageSize.width() ) && ( len < string.length() ) )
			++len;
		--len;
		//check if we in word
		if (( string[ len - 1 /*last char in line*/ ] != ' ' )
		        && ( string[ len /*1st char of next line*/ ] != ' ' ))
		{
			//find last word
			int i = wordAt( string, len );
			//check wheather its width less than page width
			if ( fm.width( getWord( string, i ) ) < m_pageSize.width() )
			{
				//if so, move last word to the next line
				QString jstring = string.left( i );
				m_lines << jstring.stripWhiteSpace();
				string = string.right( string.length() - i );
			}
			else
			{
				//if its width greater than page width - split it
				m_lines << string.left( len );
				string = string.right( string.length() - len );
			}
		}
		else
		{
			m_lines << string.left( len );
			if ( string[ len ] == ' ' )
			{
				string = string.right( string.length() - len - 1 );
			}
			else
				string = string.right( string.length() - len );
		}
	}
	m_lines << string;
}

QString Renderer::getWord( const QString & str, int idx )
{
	//TODO: rewrite without regexp
	static QRegExp rx( "\\s" );
	int pos = rx.search(str, idx);
	if (pos != -1)
	{
		QString tmp(str.mid(idx, pos - idx));
		if ( tmp[ 0 ] == ' ' )
			kdDebug() << "space" << endl;
		return tmp;
	}
	QString tmp(str.right(str.length() - idx));
	if ( tmp[ 0 ] == ' ' )
		kdDebug() << "scpae 2" << endl;
	return tmp;
}

int Renderer::wordAt(const QString & string, int len)
{
	while (--len >= 0)
		if (string[len] == ' ')
			return ++len;
	return 0;
}

void Renderer::setFont( const QFont & font )
{
	m_font = font;
	render();
}

void Renderer::setPageSize( const QSize & size )
{
	m_pageSize = size;
}

void Renderer::drawPage( QPainter & paint, QRect rect, int pageNumber )
{
	QFontMetrics fm( font() );
	int h = fm.height();
	int line = 1;
	if ( m_lines.count() )
	{
		typedef QStringList::const_iterator SI;
		SI end = m_lines.constEnd();
		SI it = m_lines.at( pageNumber * m_linesPerPage );
		while ( it != end && ( line <= m_linesPerPage ) )
		{
			drawLine( paint, rect.left(), rect.top() + ( line ) * h, *it );
			++line;
			++it;
		}
	}
}

void Renderer::drawLine( QPainter & paint, int x, int y, const QString & string )
{
	//TODO: Optimize this stuff
	QString str = string;

	int len = str.length();
	if ( str[0] == START_PARAGRAPH && str[len-1] == END_PARAGRAPH )
	{
		paint.drawText( x, y, str );
		return;
	}

	if ( str[ str.length() -1 ] == END_PARAGRAPH )
	{
		str.truncate( str.length() - 1 );
		paint.drawText( x, y, str );
		return;
	}

	while ( str.length() && ( str[ str.length() - 1 ] == ' ' ) )
		str.truncate( str.length() - 1 );

	QFontMetrics fm( font() );
	int width = m_pageSize.width();
	int cur_width = fm.width( string );
	int space_width = fm.width( " " );
	//kdDebug() << "here" << endl;
	if ( cur_width < width )
	{
		long int pos = 0, off = 0;
		int space_count = 0;
		while ( ( ( pos = str.find( " ", off ) ) != -1 ) && ( pos != str.length() - 1 ) )
		{
			//kdDebug() << "pos = " << pos << endl;
			//kdDebug() << "off = " << off << endl;
			off = pos + 1;
			++space_count;
		}
		//kdDebug() << "space_count = " << space_count << endl;
		if ( space_count )
		{
			int avg_len = (int) ((double)( width - cur_width ) / (double)space_count);
			int change = width - cur_width - avg_len * space_count;

			int idx = 0;
			pos = off = 0;
			while ( ( ( pos = str.find( ' ', off ) ) != -1 ) && ( pos != str.length() - 1 ) )
			{
				//kdDebug() << "idx = " << idx << endl;
				//kdDebug() << "pos = " << pos << endl;
				if ( idx < pos )
				{
					paint.drawText( x, y, str.mid( idx, pos - idx ) );
					x += fm.width( str.mid( idx, pos - idx ) );
				}
				x += space_width + avg_len;
				//x += avg_len;
				idx = off = pos + 1;
				//idx = pos+1;
			}
			paint.drawText( x + change, y, str.right( str.length() - idx ) );
		}
		else
			paint.drawText( x, y, str );
	}
	else
		paint.drawText( x, y, str );
}

Paragraph::Paragraph()
	:m_width(0)
{
}

Paragraph::Paragraph(const QString & a_str)
	:m_text(a_str), m_width(0)
{
}

Paragraph::Paragraph( const QString & a_str, long a_width )
	:m_text(a_str), m_width(a_width)
{
}

#include "renderer.moc"
